`timescale 1ns / 1ps
//Name: Robert Smith
//PID: A08609119
//Name: Shreenidhi Chowkwale
//PID: A09089080

module alu#(parameter OP_CODE_WIDTH = 5, D_WIDTH = 34)
(
	input [OP_CODE_WIDTH - 1 : 0] op_code,
	input [D_WIDTH - 1 : 0] d0_i,
	input [D_WIDTH - 1 : 0] d1_i,
	input [D_WIDTH - 1 : 0] op_reg_i,
	output [D_WIDTH - 1 : 0] d_o,
	output branch_o
);

	wire [D_WIDTH - 1 : 0] twos_comp = ~d1_i + 1;
	
	reg [D_WIDTH - 1 : 0] d0, d1;
	
	reg [D_WIDTH - 1 : 0] d_o_next;
	reg branch_o_next;
	
	wire is_sub = op_code == 5'b00010 || op_code == 5'b00011;
	//is add, addi, sub, subi, ldinst, ldr, sw
	wire is_add = op_code == 5'b00000 || op_code == 5'b00001
		|| is_sub || op_code == 5'b01000 || op_code == 5'b01100 || op_code == 5'b01101;
		
	wire is_srl = op_code == 5'b00100;
	wire is_nor = op_code == 5'b00101;
	
	wire is_bgt = op_code == 5'b11000;
	wire is_bne = op_code == 5'b11001;
	wire is_swtch = op_code == 5'b10111;

	always_comb
		begin
			d0 = d0_i;
			if(is_sub)
				d1 = twos_comp;
			else
				d1 = d1_i;
			if(is_add)
				d_o_next = d0 + d1;
			else if(is_srl)
				d_o_next = d0 >> d1;
			else if(is_nor)
				d_o_next = ~(d0 | d1);
			else
				d_o_next = 34'b0;
				

			// This has to be fixed since this does not compare with two's complement in mind
			if(is_bgt)
				branch_o_next = ($signed(d0) > $signed(d1));
			else if(is_bne)
				branch_o_next = d0 != d1;
			else if(is_swtch)
				branch_o_next = op_reg_i == 34'b0;
			//If there is no branch, a restart happens, so this is always 1 unless the other branches makes it 0.
			else
				branch_o_next = 1'b1;
		end
		
	assign d_o = d_o_next;
	assign branch_o = branch_o_next;

endmodule

